package bma.common.thrift;

import java.net.URI;
import java.net.URISyntaxException;

import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TJSONProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TTransport;

import bma.common.langutil.core.ExceptionUtil;
import bma.common.langutil.core.SizeUtil;
import bma.common.langutil.core.SizeUtil.Unit;
import bma.common.langutil.core.StringUtil;
import bma.common.langutil.core.ToStringUtil;
import bma.common.langutil.core.ValueUtil;
import bma.common.langutil.http.QueryStringDecoder;
import bma.common.langutil.io.HostPort;

public class ThriftClientConfig {
	public static final String TYPE_SOCKET = "socket";
	public static final String TYPE_HTTP = "http";

	protected String type = TYPE_SOCKET;
	protected HostPort host;
	protected String url;
	protected String module;
	protected int frameMaxLength = -1;
	protected String protocol;
	protected boolean noneBlock;

	public boolean isNoneBlock() {
		return noneBlock;
	}

	public void setNoneBlock(boolean noneBlock) {
		this.noneBlock = noneBlock;
	}

	public String getProtocol() {
		return protocol;
	}

	public void setProtocol(String protocol) {
		this.protocol = protocol;
	}

	public String getModule() {
		return module;
	}

	public void setModule(String module) {
		this.module = module;
	}

	public int getFrameMaxLength() {
		return frameMaxLength;
	}

	public void setFrameMaxLength(int frameBuffer) {
		this.frameMaxLength = frameBuffer;
	}

	public void setFrameSize(String sz) {
		try {
			this.frameMaxLength = (int) SizeUtil.convert(sz, 1024, Unit.B);
		} catch (Exception e) {
			throw ExceptionUtil.throwRuntime(e);
		}
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public boolean isHttp() {
		return StringUtil.equals(TYPE_HTTP, type);
	}

	public boolean isSocket() {
		if (ValueUtil.empty(type))
			return true;
		return StringUtil.equals(TYPE_SOCKET, type);
	}

	public HostPort getHost() {
		return host;
	}

	public void setHost(HostPort host) {
		this.host = host;
	}

	public void setHostPort(String hostport) {
		this.host = new HostPort();
		this.host.setHostString(hostport, 9090);
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public TProtocol createProtocol(TTransport trans, String moduleName) {
		TProtocol tprotocol = null;
		if (StringUtil.equalsIgnoreCase(this.protocol, "json")) {
			tprotocol = new TJSONProtocol(trans);
		} else {
			tprotocol = new TBinaryProtocol(trans);
		}
		String m = moduleName == null ? module : moduleName;
		if (ValueUtil.notEmpty(m)) {
			tprotocol = new TModuleProtocol(tprotocol, m);
		}
		return tprotocol;
	}

	public static ThriftClientConfig fromEntry(String entry) {
		if (ValueUtil.empty(entry))
			return null;
		ThriftClientConfig cfg = new ThriftClientConfig();
		URI uri = null;
		try {
			uri = new URI(entry);
		} catch (URISyntaxException e) {
			throw ExceptionUtil.throwRuntime(e);
		}

		String scheme = uri.getScheme();
		if (ThriftClientConfig.TYPE_HTTP.equalsIgnoreCase(scheme)) {
			cfg.setType(ThriftClientConfig.TYPE_HTTP);
			cfg.setUrl(entry);
		} else if (ThriftClientConfig.TYPE_SOCKET.equalsIgnoreCase(scheme)) {
			cfg.setType(ThriftClientConfig.TYPE_SOCKET);
			HostPort host = new HostPort();
			host.setHost(uri.getHost());
			if (uri.getPort() != -1) {
				host.setPort(uri.getPort());
			}
			cfg.setHost(host);
		} else {
			throw new IllegalArgumentException("unknow scheme [" + scheme + "]");
		}

		QueryStringDecoder query = new QueryStringDecoder(uri);
		String module = query.getParameter("_module");
		if (ValueUtil.notEmpty(module)) {
			cfg.setModule(module);
		}
		String frameSize = query.getParameter("_frameSize");
		if (ValueUtil.notEmpty(frameSize)) {
			cfg.setFrameSize(frameSize);
		}
		String frameLength = query.getParameter("_frameLength");
		if (ValueUtil.notEmpty(frameLength)) {
			cfg.setFrameMaxLength(ValueUtil.intValue(frameLength, 0));
		}
		String protocol = query.getParameter("_protocol");
		if (ValueUtil.notEmpty(protocol)) {
			cfg.setProtocol(protocol);
		}
		String nblock = query.getParameter("_noneblock");
		if (ValueUtil.notEmpty(nblock)) {
			cfg.setNoneBlock(ValueUtil.booleanValue(nblock, false));
		}

		return cfg;
	}

	public String toEntry() {
		if (this.type.equals(TYPE_HTTP)) {
			return this.url;
		} else {
			StringBuilder sb = new StringBuilder();
			sb.append("socket://").append(this.host).append("/?");
			if (ValueUtil.notEmpty(module)) {
				sb.append("_module=").append(module).append("&");
			}
			if (ValueUtil.notEmpty(module)) {
				sb.append("_module=").append(module).append("&");
			}
			if (frameMaxLength >= 0) {
				sb.append("_frameLength=").append(frameMaxLength).append("&");
			}
			if (ValueUtil.notEmpty(protocol)) {
				sb.append("_protocol=").append(protocol).append("&");
			}
			if (!noneBlock) {
				sb.append("_noneblock=").append(noneBlock).append("&");
			}
			return sb.toString();
		}
	}

	@Override
	public String toString() {
		return ToStringUtil.fieldReflect(this);
	}
}
